package com.boyadegroot.divelog.ui.diver;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Vibrator;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.boyadegroot.divelog.R;
import com.boyadegroot.divelog.data.DiveLogData;
import com.boyadegroot.divelog.models.Diver;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class DiverPage extends Fragment {

    private static final String TAG = DiverPage.class.getName();

    private static final int DIVER_IMAGE_REQUEST = 0;
    private static final String DIVER_IMAGE_FOLDER = "diver_images";

    private Diver mDiver;

    private ImageView mImage;
    private TextView mUsername;
    private TextView mDives;
    private ImageView mDivesIcon;
    private TextView mCertification;
    private LinearLayout mImageTextLayout;

    public static DiverPage newInstance(Diver diver) {
        DiverPage instance = new DiverPage();
        Bundle args = new Bundle();
        args.putParcelable("diver", diver);
        instance.setArguments(args);
        return instance;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        if (args != null) {
            mDiver = getArguments().getParcelable("diver");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View fragmentView = inflater.inflate(R.layout.page_diver, container, false);
        createView(fragmentView);
        setDiverImage();
        return fragmentView;
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == DIVER_IMAGE_REQUEST) {
            if (resultCode == Activity.RESULT_OK) {
                Uri imageUri = data.getData();
                // Log.d(TAG, "Trying to save image for diver with id = " + diverId + ": " + imageUri);
                int imageWidth = mImage.getMeasuredWidth();
                int imageHeight = mImage.getMeasuredHeight();
                Activity activity = getActivity();
                File imageDirectory = activity.getDir(DIVER_IMAGE_FOLDER, Context.MODE_PRIVATE);
                File imageFile = getDiverImageFile();
                Bitmap.CompressFormat imageFormat = Bitmap.CompressFormat.PNG;
                int imageQuality = 100;
                new SaveScaledImageTask(imageDirectory, imageFile, imageWidth, imageHeight, imageFormat, imageQuality).execute(imageUri);
            }
        }
    }

    private void onScaledImageSaved() {
        // Log.v(TAG, "onScaledImageSaved()");
        setDiverImage();
    }

    private void setDiverImage() {
        File imageFile = getDiverImageFile();
        if (imageFile.exists()) {
            String imagePath = imageFile.getAbsolutePath();
            Bitmap image = BitmapFactory.decodeFile(imagePath);
            if (image == null) {
                Log.e(TAG, "Could not read image: " + imagePath);
            }
            mImage.setImageBitmap(image);
            mImageTextLayout.setBackgroundResource(R.drawable.shape_gradient);
        } else {
            mImage.setImageBitmap(null);
            mImageTextLayout.setBackgroundResource(0);
        }
    }

    private File getDiverImageFile() {
        long diverId = mDiver.getId();
        Activity activity = getActivity();
        File imageDirectory = activity.getDir(DIVER_IMAGE_FOLDER, Context.MODE_PRIVATE);
        File imageFile = new File(imageDirectory, Long.toString(diverId));
        return imageFile;
    }

    private int calculateInSampleSize(Uri imageUri, int minimumWidth, int minimumHeight) {
        // Log.v(TAG, "calculateInSampleSize(imageUri = " + imageUri + ", minimumWidth = " + minimumWidth + ", minimumHeight = " + minimumHeight + ")");
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            Activity activity = getActivity();
            ContentResolver resolver = activity.getContentResolver();
            InputStream imageStream = resolver.openInputStream(imageUri);
            BitmapFactory.decodeStream(imageStream, null, options);
            int currentHeight = options.outHeight;
            int currentWidth = options.outWidth;
            int inSampleSize = 1;
            if (currentHeight > minimumHeight || currentWidth > minimumWidth) {
                int heightRatio = Math.round((float) currentHeight / (float) minimumHeight);
                int widthRatio = Math.round((float) currentWidth / (float) minimumWidth);
                inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
            }
            // Log.d(TAG, "return " + inSampleSize);
            return inSampleSize;
        } catch (FileNotFoundException e) {
            Log.e(TAG, "Could not open file = " + imageUri + ": " + e.getMessage());
            return -1;
        }
    }

    private void createView(View fragmentView) {
        getViewElements(fragmentView);
        String username = mDiver.getUsername();
        mUsername.setText(username);
        String certification = mDiver.getCertificationName();
        if (certification != null) {
            mCertification.setText(certification);
        }
        Activity activity = getActivity();
        DiveLogData data = DiveLogData.getInstance(activity);
        int divesCount = data.getDivesCount(mDiver.getId());
        if (divesCount > 0) {
            Resources resources = getResources();
            mDives.setText(resources.getQuantityString(R.plurals.text_dives, divesCount, divesCount));
            mDivesIcon.setVisibility(View.VISIBLE);
        } else {
            mDives.setText("");
            mDivesIcon.setVisibility(View.INVISIBLE);
        }
        setDiverImageListener();
    }

    public Diver getDiver() {
        return mDiver;
    }

    private void setDiverImageListener() {
        mImage.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                Activity activity = getActivity();
                Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
                vibrator.vibrate(100);
                Intent intent = new Intent();
                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                intent.addCategory(Intent.CATEGORY_OPENABLE);
                startActivityForResult(intent, DIVER_IMAGE_REQUEST);
                return true;
            }
        });
    }

    private void getViewElements(View fragmentView) {
        mImage = (ImageView) fragmentView.findViewById(R.id.image);
        mUsername = (TextView) fragmentView.findViewById(R.id.username);
        mDives = (TextView) fragmentView.findViewById(R.id.dives);
        mDivesIcon = (ImageView) fragmentView.findViewById(R.id.dives_icon);
        mCertification = (TextView) fragmentView.findViewById(R.id.certification);
        mImageTextLayout = (LinearLayout) fragmentView.findViewById(R.id.imagetextlayout);
    }

    private class SaveScaledImageTask extends AsyncTask<Uri, Void, Boolean> {

        File mDirectory;
        File mImageFile;
        int mWidth;
        int mHeight;
        Bitmap.CompressFormat mFormat;
        int mQuality;

        public SaveScaledImageTask(File directory, File imageFile, int width, int height, Bitmap.CompressFormat format, int quality) {
            this.mDirectory = directory;
            this.mImageFile = imageFile;
            this.mWidth = width;
            this.mHeight = height;
            this.mFormat = format;
            this.mQuality = quality;
        }

        protected Boolean doInBackground(Uri... uris) {
            Uri uri = uris[0];
            boolean result = saveScaledImage(uri, mDirectory, mImageFile, mWidth, mHeight, mFormat, mQuality);
            return result;
        }

        protected void onPostExecute(Boolean result) {
            if (result) {
                onScaledImageSaved();
            }
        }

        private boolean saveScaledImage(Uri uri, File directory, File imageFile, int width, int height, Bitmap.CompressFormat format, int quality) {
            Bitmap scaledBitmap = getScaledBitmap(uri, width, height);
            if (saveBitmapToFile(scaledBitmap, imageFile, directory, format, quality)) {
                // Log.d(TAG, "Image saved: " + imageFile.getAbsolutePath());
                return true;
            } else {
                Log.e(TAG, "Could not save image: " + imageFile.getAbsolutePath());
                return false;
            }
        }

        private Bitmap getScaledBitmap(Uri uri, int minimumWidth, int minimumHeight) {
            // Log.v(TAG, "getScaledBitmap(uri = " + uri + ", minimumWidth = " + minimumWidth + ", minimumHeight = " + minimumHeight + ")");
            try {
                BitmapFactory.Options options = new BitmapFactory.Options();
                int inSampleSize = calculateInSampleSize(uri, minimumWidth, minimumHeight);
                if (inSampleSize == -1) {
                    Log.e(TAG, "Could not calculate image scale");
                    return null;
                }
                options.inSampleSize = inSampleSize;
                options.inJustDecodeBounds = false;
                Activity activity = getActivity();
                ContentResolver resolver = activity.getContentResolver();
                InputStream imageStream = resolver.openInputStream(uri);
                Bitmap scaledImage = BitmapFactory.decodeStream(imageStream, null, options);
                return scaledImage;
            } catch (FileNotFoundException e) {
                Log.e(TAG, "Could not open file = " + uri + ": " + e.getMessage());
                return null;
            }
        }

        private boolean saveBitmapToFile(Bitmap image, File file, File folder, Bitmap.CompressFormat format, int quality) {
            // Log.v(TAG, "saveBitmapToFile(Bitmap image, file = " + file.getAbsolutePath() + ", folder = " + folder.getAbsolutePath() + ", Bitmap.CompressFormat format, quality = " + quality + ")");
            try {
                FileOutputStream fos = new FileOutputStream(file);
                // Log.d(TAG, "FileOutputStream created");
                if (image.compress(format, quality, fos)) {
                    // Log.d(TAG, "Image correctly saved to file");
                    return createNomediaFile(folder);
                } else {
                    Log.e(TAG, "Error saving bitmap to compressed file");
                    return false;
                }
            } catch (FileNotFoundException e) {
                Log.e(TAG, "Error saving file = " + file.getAbsolutePath() + ": " + e.getMessage());
                return false;
            }
        }

        private boolean createNomediaFile(File directory) {
            File nomedia = new File(directory, ".nomedia");
            try {
                nomedia.createNewFile();
            } catch (IOException e) {
                Log.e(TAG, "Error creating .nomedia file: " + e.getMessage());
                return false;
            }
            return true;
        }
    }
}